package com.yy.bootdemo.admin.aspectj;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yy.bootdemo.common.exceptionhandler.MyException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @Author Owen
 * @Date 2020/8/7
 * @DescriptionAOP系统操作日志
 */
@Slf4j
@Aspect
@Component

@Order(2)
public class SystemLogAspect {



    //切入@RequestMapping注解
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void getRequestMapping() {
    }

    //切入@PutMapping注解
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping)")
    public void getPutMapping() {
    }

    //切入@PostMapping注解
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void getPostMapping() {
    }

    //切入@PostMapping注解
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void getGetMapping() {
    }

    //切入@DeleteMapping注解
    @Pointcut("@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    public void DeleteMapping() {
    }

    //自定义日志保存注解
    @Pointcut("@annotation(com.yy.bootdemo.admin.annotation.DataPermission)")
    public void LogRecord() {
    }

    //@Around 环绕通知:目标方法执行之前和之后都可以执行
    @Around("getPostMapping()")
    public Object postAround(final ProceedingJoinPoint point) throws Throwable {
        return doAround(point);
    }

    @Around("getPutMapping()")
    public Object putAround(final ProceedingJoinPoint point) throws Throwable {
        return doAround(point);
    }

    @Around("DeleteMapping()")
    public Object deleteAround(final ProceedingJoinPoint point) throws Throwable {
        return doAround(point);
    }

    @Around("getRequestMapping()")
    public Object requestMappingAround(final ProceedingJoinPoint point) throws Throwable {
        return doAround(point);
    }

    @Around("getGetMapping()")
    public Object getAround(final ProceedingJoinPoint point) throws Throwable {
        return doAround(point);
    }

    /**
     * @author: Owen
     * @date: 2021/6/30
     * @description:系统保存
     */
    @Around("LogRecord()")
    public Object LogRecord(final ProceedingJoinPoint point) throws Throwable {
        return saveLog(point);
    }

    /**
     * @author: Owen
     * @date: 2021/6/30
     * @description:Controller视图层(环绕通知)
     */
    private Object doAround(ProceedingJoinPoint point) throws Throwable {
        Method m = ((MethodSignature) point.getSignature()).getMethod();//获取方法数据
        String signature = point.getSignature().toString();//业务详情
        String[] type = signature.split("client");
        long startTime = System.currentTimeMillis();//开始请求时间
        String typeName = m.getReturnType().getName();//返回类型
        Object proceedResult;//返回结果对象
        try {
            proceedResult = point.proceed();
            long endTime = System.currentTimeMillis();//结束时间
            long costTime = endTime - startTime;//接口耗时
            if (type.length <= 1) {
                log.info("\n======= 《接口调用成功》 ========" + "\n接口详情：" + signature + "\n接口参数：" + Arrays.asList(point.getArgs()) + "\n请求耗时：" + costTime + " ms");
            }
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();//结束时间
            long costTime = endTime - startTime;//接口耗时
            if (type.length > 1) {
                log.error("\n======= 《跨服务调用异常》 ========" + "\n请求参数：" + Arrays.asList(point.getArgs()) + "\n接口详情：" + signature + "\n请求结果：" + e + "\n请求耗时：" + costTime + " ms", e);
            } else {
                log.error("\n======= 《接口调用异常》 ========" + "\n请求参数：" + Arrays.asList(point.getArgs()) + "\n接口详情：" + signature + "\n请求结果：" + e + "\n请求耗时：" + costTime + " ms", e);
            }
            throw new MyException(StringUtils.isBlank(e.getMessage())?"接口请求失败！":e.getMessage());
        }
        return proceedResult;
    }


    /**
     * @author: Owen
     * @date: 2021/6/30
     * @description:系统敏感操作(日志保存)
     */
    private Object saveLog(ProceedingJoinPoint point) {
        Object result = null;    //业务详情
        String error = null; //业务异常详情
        //请求开始时间
        long beginTime = System.currentTimeMillis();
        try {
            result = point.proceed();
        } catch (Throwable throwable) {
            //异常详情
            error = throwable.getMessage();
            log.error("System log business throwable：" + throwable.getMessage());
        }

        //构建参数 创建实例
        String errorInfo = error;//错误详情

        return result;
    }

}
